﻿using BaseFramework;
using BaseFramework.Core;
using BaseFramework.DbConnectionProvider;
using LiteFramework.Contract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LiteFramework.Server.Component
{
    public class PermissionComponent : IPermissionContract
    {
        IDbConnectionProvider _connectionProvider = null;
        public PermissionComponent(IDbConnectionProvider connectionProvider = null)
        {
            _connectionProvider = connectionProvider;
            if (_connectionProvider == null) _connectionProvider = ServerApplication.DefaultConnectionProvider();
        }

        public IDbConnectionProvider SqlHelper { get { return _connectionProvider; } }

        #region Task
        public Model.Task GetTask(Guid id)
        {
            return PersistentEntityMediator<Model.Task>.Get(_connectionProvider, id);
        }

        public Model.Task[] GetAllTasks()
        {
            return PersistentEntityMediator<Model.Task>.GetList(_connectionProvider);
        }

        public string GetTaskName(string taskCode)
        {
            var model = PersistentEntityMediator<Model.Task>.Get(_connectionProvider, BaseFramework.Expression.Eq("Code", taskCode));
            return model != null ? model.Name : string.Empty;
        }
        #endregion

        #region Role
        public Model.Role[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        public Model.Role GetDefaultRole()
        {
            throw new NotImplementedException();
        }

        public Model.Role GetRole(Guid id)
        {
            throw new NotImplementedException();
        }

        public Model.Role GetRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public Guid SaveRole(Model.Role role)
        {
            throw new NotImplementedException();
        }

        public void RemoveRole(Model.Role role)
        {
            throw new NotImplementedException();
        }

        public void RemoveRole(params Guid[] ids)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Password
        public bool IsSecurePassword(string password)
        {
            if (String.IsNullOrEmpty(password))
                return false;
            else if (password.Length > 0 && password.TrimStart(password[0]).Length == 0)
                return false;
            else if (String.Compare(password, SystemResources.DEFAULT_PASSWORD_VALUE, true) == 0)
                return false;
            //else if (String.Compare(password, GetDefaultPassword(), true) == 0)
            //    return false;
#warning 未判定是否与默认密码一样
            else
                return true;
        }

        public bool Validate(string password)
        {
            string err;
            if (!InternalHelper.ValidateUser(this.SqlHelper, ServerApplication.User.UserName, password, out err))
                throw new AccessSecurityException(err);

            return true;
        }

        public void ResetPassword(object state, Model.User user)
        {
            this._validUser(user, true);

            if (user != null && !AdditionalAuthenticate(user, state))
            {
                throw new AccessSecurityException("因为无法验证用户 " + user.UserName + "，重置密码失败。");
            }
            else
            {
                var newSalt = Guid.NewGuid().ToString("N");
                var newHash = InternalHelper.HashPwd(this.GetDefaultPassword(), newSalt);
                var param0 = this.SqlHelper.CreateParameter("PasswordSalt", newSalt);
                var param1 = this.SqlHelper.CreateParameter("Password", newHash);
                var param2 = this.SqlHelper.CreateParameter("UserName", user.UserName);
                var sql = string.Format("UPDATE SYS_User SET Password={0}, PasswordSalt={1} WHERE UserName={2}", param1.ParameterName, param2.ParameterName);
                if ((int)this.SqlHelper.ExecScalar(sql, param0, param1, param2) <= 0)
                    throw new AccessSecurityException("重置密码失败。");
                else
                    _writeLog_User("重置用户 " + user.UserName + " 的密码。");
            }
        }

        public void ResetPassword(object state, params int[] ids)
        {
            if (ids != null && ids.Length > 0)
            {
                foreach (int id in ids)
                {
                    this.ResetPassword(state, this.GetUser(id));
                }
            }
        }

        public void ChangePassword(string oldPassword, string newPassword)
        {
            var user = ServerApplication.User;
            if (user.LockPassword)
                throw new AccessSecurityException("您的密码被锁定为不允许修改，请联系管理员。");

            string err = null;
            if (!InternalHelper.ValidateUser(this.SqlHelper, user.UserName, oldPassword, out err))
                throw new AccessSecurityException(err);

            if (!this.Validate(newPassword))
                throw new AccessSecurityException("您的新密码强度太低");

            var newSalt = Guid.NewGuid().ToString("N");
            var newHash = InternalHelper.HashPwd(newPassword, newSalt);
            var param0 = this.SqlHelper.CreateParameter("PasswordSalt", newSalt);
            var param1 = this.SqlHelper.CreateParameter("Password", newHash);
            var param2 = this.SqlHelper.CreateParameter("UserName", user.UserName);
            var sql = string.Format("UPDATE SYS_User SET Password={0}, PasswordSalt={1} WHERE UserName={2}", param1.ParameterName, param2.ParameterName);
            if ((int)this.SqlHelper.ExecScalar(sql, param0, param1, param2) <= 0)
                throw new AccessSecurityException("用户名不存在");

            _writeLog_User("更改用户 " + user.UserName + " 的密码。");
        }

        public void ChangePIN(Model.User[] users, string newPin)
        {
            var expression = Expression.In("UserName", users.Select(i => i.UserName).ToArray());
            var models = PersistentEntityMediator<Model.User>.GetList(this.SqlHelper, expression);

            if (models != null && models.Length != 0)
            {
                StringBuilder msg = new StringBuilder((!String.IsNullOrEmpty(newPin) ? "更改用户 " : "撤销用户 "));

                foreach (var user in models)
                {
                    if (!String.IsNullOrEmpty(newPin))
                    {
                        byte[] pin = LiteFramework.Security.DES.EncryptExt(newPin, user.ID.ToString());
                        user.InternalBag.SetValue("SecurityPin", Convert.ToBase64String(pin));
                    }
                    else
                    {
                        user.InternalBag.SetValue("SecurityPin", null);
                    }

                    string err = null;
                    PersistentEntityMediator<Model.User>.Update(this.SqlHelper, user, out err);

                    msg.Append(user.UserName);
                    if (models.Length > 1)
                        msg.Append(",");
                }

                msg.Append(" 的安全身份验证信息(PIN)。");
                _writeLog_User(msg.ToString());
            }
        }
        #endregion

        #region User

        public Model.User GetUser()
        {
            var userName = this._getCurrentUserName();
            return this.GetUser(userName);
        }

        public Model.UserNameChoice GetUser2()
        {
            return Model.User.ToChoice(GetUser());
        }

        public bool ExistUserName(string userName)
        {
            if (string.IsNullOrEmpty(userName)) return false;
            var expression = Expression.Eq("UserName", userName);
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public bool ExistUserName(string userName, bool ignoreSelf)
        {
            if (string.IsNullOrEmpty(userName)) return false;
            var expression = Expression.Eq("UserName", userName);
            if (ignoreSelf)
            {
                var self = this.GetUser();
                if (self != null && !string.IsNullOrEmpty(self.UserName))
                    expression.And(Expression.NotEq("UserName", self.UserName));
            }
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public bool ExistNickName(string nickName)
        {
            if (string.IsNullOrEmpty(nickName)) return false;
            var expression = Expression.Eq("NiceName", nickName);
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public bool ExistNickName(string nickName, bool ignoreSelf)
        {
            if (string.IsNullOrEmpty(nickName)) return false;
            var expression = Expression.Eq("NiceName", nickName);
            if (ignoreSelf)
            {
                var self = this.GetUser();
                if (self != null && !string.IsNullOrEmpty(self.NickName))
                    expression.And(Expression.NotEq("NiceName", self.NickName));
            }
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public bool ExistEmail(string email)
        {
            if (string.IsNullOrEmpty(email)) return false;
            var expression = Expression.Eq("Email", email);
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public bool ExistEmail(string email, bool ignoreSelf)
        {
            if (string.IsNullOrEmpty(email)) return false;
            var expression = Expression.Eq("Email", email);
            if (ignoreSelf)
            {
                var self = this.GetUser();
                if (self != null && !string.IsNullOrEmpty(self.Email))
                    expression.And(Expression.NotEq("Email", self.Email));
            }
            return PersistentEntityMediator<Model.User>.Exist(this._connectionProvider, expression);
        }

        public Model.User GetUser(int id)
        {
            if (id <= 0) return null;
            return PersistentEntityMediator<Model.User>.Get(this._connectionProvider, id);
        }

        public Model.UserNameChoice GetUser2(int id)
        {
            if (id <= 0) return null;
            return Model.User.ToChoice(GetUser(id));
        }

        public Model.User GetUser(string userName)
        {
            if (string.IsNullOrEmpty(userName)) return null;
            return PersistentEntityMediator<Model.User>.FindOne(this._connectionProvider, Expression.Eq("UserName", userName));
        }

        public Model.User GetUserByOpenId(Model.LoginType type, string openId)
        {
            if (!System.Enum.IsDefined(typeof(Model.LoginType), type) || string.IsNullOrEmpty(openId)) return null;
            var expression = Expression.Eq("LoginType", type).And(Expression.Eq("OpenId", openId));
            return PersistentEntityMediator<Model.User>.FindOne(this._connectionProvider, expression);
        }

        public Model.User[] GetAllUsers()
        {
            return PersistentEntityMediator<Model.User>.GetAll(this._connectionProvider);
        }

        public Model.User[] GetAllUsers(Enum.YesNoUnsure onlyActive)
        {
            switch (onlyActive)
            {
                case Enum.YesNoUnsure.Unsure:
                    return GetAllUsers();
                case Enum.YesNoUnsure.No:
                    return PersistentEntityMediator<Model.User>.GetList(this._connectionProvider, Expression.Eq("IsActive", false));
                case Enum.YesNoUnsure.Yes:
                default:
                    return PersistentEntityMediator<Model.User>.GetList(this._connectionProvider, Expression.Eq("IsActive", true));
            }
        }

        public Model.User[] GetAllUsers(Guid companyID, Enum.YesNoUnsure onlyActive)
        {
            if (companyID == Guid.Empty) throw Error.ArgumentNull("companyID");

            var expression = Expression.Eq("CompanyID", companyID);
            switch (onlyActive)
            {
                case Enum.YesNoUnsure.Yes:
                    expression.And(Expression.Eq("IsActive", true));
                    break;
                case Enum.YesNoUnsure.No:
                    expression.And(Expression.Eq("IsActive", false));
                    break;
            }

            return PersistentEntityMediator<Model.User>.GetList(this._connectionProvider, expression);
        }

        public Model.User[] GetAllUsers(BaseFramework.SearchParam searchParam, ref BaseFramework.PageParam pageParam, Enum.YesNoUnsure onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetAllUsers2(Enum.YesNoUnsure onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetAllUsers2(Guid companyID, Enum.YesNoUnsure onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetAllUsers2(BaseFramework.SearchParam searchParam, ref BaseFramework.PageParam pageParam, Enum.YesNoUnsure onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetUserByCompany(bool onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetUserByCompany(Model.Company company, bool onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.UserNameChoice[] GetUserByCompany(Guid companyID, bool onlyActive)
        {
            throw new NotImplementedException();
        }

        public Model.User[] GetUser(Model.OrganizationNameChoice organization, bool includeSub, BaseFramework.SearchParam searchParam, ref BaseFramework.PageParam pageParam)
        {
            throw new NotImplementedException();
        }

        public Model.User[] GetUserWithRole(Model.OrganizationNameChoice organization, bool includeSub, string[] roleCodes, BaseFramework.SearchParam searchParam, ref BaseFramework.PageParam pageParam)
        {
            throw new NotImplementedException();
        }

        public Model.User[] GetUserWithTask(Model.OrganizationNameChoice organization, bool includeSub, string[] taskCodes, BaseFramework.SearchParam searchParam, ref BaseFramework.PageParam pageParam)
        {
            throw new NotImplementedException();
        }

        public int SaveUser(Model.User user)
        {
            throw new NotImplementedException();
        }

        public bool RemoveUser(Model.User user)
        {
            throw new NotImplementedException();
        }

        public int RemoveUser(params int[] ids)
        {
            throw new NotImplementedException();
        }

        public string GetDefaultEmailSuffix()
        {
            throw new NotImplementedException();
        }

        public bool ActiveUser(bool active, Model.User user)
        {
            throw new NotImplementedException();
        }

        public int ActiveUser(bool active, params int[] ids)
        {
            throw new NotImplementedException();
        }

        public bool UnlockUser(Model.User user)
        {
            throw new NotImplementedException();
        }

        public int UnlockUser(params int[] ids)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Internal

        internal void RemoveUserFromCache(Model.User user)
        {
            ServerApplication.Cache.IsolatedRemove(user.ProviderUserKey);
        }

        /// <summary>
        /// 附加验证
        /// </summary>
        /// <param name="user"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        internal bool AdditionalAuthenticate(Model.User user, object state)
        {
            string b64 = user.InternalBag.GetValue("SecurityPin", null);

            if (String.IsNullOrEmpty(b64))   // 不进行附加的验证
            {
                return (state == null);
            }
            else
            {
                string pin = null;

                try
                {
                    if (b64.Split(',').Length == 5) //格式为111111,22222,3333333,44444 的DN
                    {
                        pin = b64;
                    }
                    else //Base64位的字符串
                    {
                        pin = LiteFramework.Security.DES.Decrypt(Convert.FromBase64String(b64), user.ID.ToString());
                    }
                }
                catch
                {
                    return false;
                }

                // 进行附加的验证
                IAdditionalAuthentication additionalAuth = ServerApplication.ComponentFactory.Create<IAdditionalAuthentication>();
                if (additionalAuth == null) additionalAuth = new DefaultAdditionalAuthentication();

                return additionalAuth.Authenticate(pin, state);
            }
        }

        #endregion

        #region private

        /// <summary>
        /// 获取默认密码
        /// </summary>
        /// <returns></returns>
        private string GetDefaultPassword()
        {
            //string value = null;

            //using (ApproleScope scope = new ApproleScope())
            //{
            //    IGeneralContract comp = ServerApplication.ComponentFactory.Create<IGeneralContract>();
            //    SettingsItem settingsItem = comp.GetSystemDefaultSettings(SystemResources.DEFAULT_PASSWORD_KEY);
            //    if (settingsItem != null)
            //    {
            //        value = settingsItem.Value;
            //    }
            //    else
            //    {
            //        comp.SaveSystemSettings(SystemResources.DEFAULT_SECTION, SystemResources.DEFAULT_PASSWORD_KEY, SystemResources.DEFAULT_PASSWORD_VALUE, SystemResources.DEFAULT_PASSWORD_DESC, null);

            //        value = SystemResources.DEFAULT_PASSWORD_VALUE;
            //    }
            //}

            //return value.ToString();

            return "123456";
        }

        /// <summary>
        /// 判断用户名是否存在
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        private bool _existUser(string userName)
        {
            UserComponent comp = new UserComponent(this.SqlHelper);
            return comp.Exist(Expression.Eq("UserName", userName));
        }

        /// <summary>
        /// 获取当前登陆用户名
        /// </summary>
        /// <returns></returns>
        private string _getCurrentUserName()
        {
            if (System.Web.Hosting.HostingEnvironment.IsHosted)
            {
                var cur = System.Web.HttpContext.Current;
                if (cur == null || cur.User == null || cur.User.Identity == null)
                    return string.Empty;
                else
                    return cur.User.Identity.Name;
            }
            System.Security.Principal.IPrincipal user = System.Threading.Thread.CurrentPrincipal;
            if (user == null || user.Identity == null)
                return String.Empty;
            else
                return user.Identity.Name;
        }

        /// <summary>
        /// 验证用户信息
        /// </summary>
        /// <param name="user"></param>
        /// <param name="throwException"></param>
        /// <returns></returns>
        private bool _validUser(Model.User user, bool throwException)
        {
            if (user == null)
            {
                if (throwException)
                    throw new BaseException("空用户信息。");

                return false;
            }

            if (user.IsNew())
            {
                if (_existUser(user.UserName))
                {
                    if (throwException)
                        throw new BaseException(string.Format("用户 {0} 已经存在，不能建立同名用户。", user.UserName));

                    return false;
                }
            }

            if (user.IsSystem || user.IsApprole)
            {
                if (throwException)
                    throw new BaseException("不允许修改系统内置用户信息。");

                return false;
            }

            if (user.ID == ServerApplication.User.ID)
            {
                //if (user.organIDStr != ServerApplication.User.organIDStr ||
                //    user.Organization != ServerApplication.User.Organization ||
                //    user.Department != ServerApplication.User.Department ||
                //    !_isRolesEqute(user.Roles, ServerApplication.User.Roles) ||
                //    !user.Active)
                //{
                //    if (throwException)
                //        throw new BaseException("不允许修改本人所属机构、部门，以及角色权限信息。");

                //    return false;
                //}
                //else if (!user.Active)
                //{
                //    if (throwException)
                //        throw new BaseException("不允许禁用自己。");

                //    return false;
                //}
                throw new BaseException("不允许修改本人信息");
            }

            //if (ServerApplication.User.Organization != null &&
            //    !ServerApplication.User.IsSystem &&
            //    !ServerApplication.User.IsApprole &&
            //    !ServerApplication.User.IsInHQ() &&
            //    !ServerApplication.User.IsSpecial() &&
            //    user.Organization != null &&
            //    user.Organization != ServerApplication.User.Organization &&
            //    !user.Organization.IsChildOf(ServerApplication.User.Organization))
            //{
            //    if (throwException)
            //        throw new BaseException("不允许维护非本机构，或非本机构下属机构的用户信息。");

            //    return false;
            //}

            //if (!user.IsValid(ServerApplication.User))
            //{
            //    string[] error = user.GetErrorMessages();
            //    string msg = string.Empty;
            //    int count = error.Length;
            //    for (int i = 0; i < count; i++)
            //        msg += error[i];

            //    throw new BaseException(msg);
            //}

            return true;
        }

        #region Write Log

        private void _writeLog_User(string mess)
        {
            ServerApplication.WriteLog("用户", ServerApplication.LogType.Info, mess);
        }

        private void _writeLog_Role(string mess)
        {
            ServerApplication.WriteLog("角色", ServerApplication.LogType.Info, mess);
        }
        #endregion

        #endregion
    }
}